Wayland: ignore touch/tablet events on destroyed surfaces
authorwisp3rwind <wisp3rwind@posteo.eu>
Wed, 11 Nov 2020 09:12:26 +0000 (10:12 +0100)
committerwisperwind <wisp3rwind@posteo.eu>
Sun, 10 Jan 2021 11:31:37 +0000 (12:31 +0100)
When destroying a wl_surface (e.g. when a window or menu is closed), the
surface may continue to exist in the compositor slightly longer than on
the client side. In that case, the surface can still receive input
events, which need to be ignored gracefully.
In particular, this prevents segfaulting on wl_surface_get_user_data()
in that situation.

Reported in
https://gitlab.gnome.org/GNOME/gtk/-/issues/3296

The same issue for pointers/keyboards was reported in
https://bugzilla.gnome.org/show_bug.cgi?id=693338

and fixed with in
bfd7137ffbcbd8caa531d7a47d799fefb6605a5a
3625f17857328ae7e7aa43340f29efa56575a7b0
a8fc099a725543649fe3aab76943c14bdcd860fc

gdk/wayland/gdkdevice-wayland.c

index c975c2069d82d123195f9252ef3d90b760a2ad7e..5eb95ccde850965a39179551e3c5db28aa505f9f 100644 (file)
@@ -2357,6 +2357,9 @@ touch_handle_down (void              *data,
 
   _gdk_wayland_display_update_serial (display, serial);
 
+  if (!wl_surface)
+    return;
+
   touch = gdk_wayland_seat_add_touch (seat, id, wl_surface);
   touch->x = wl_fixed_to_double (x);
   touch->y = wl_fixed_to_double (y);
@@ -2404,6 +2407,9 @@ touch_handle_up (void            *data,
   _gdk_wayland_display_update_serial (display, serial);
 
   touch = gdk_wayland_seat_get_touch (seat, id);
+  if (!touch)
+    return;
+
   event = gdk_touch_event_new (GDK_TOUCH_END,
                                GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
                                touch->surface,
@@ -2442,6 +2448,9 @@ touch_handle_motion (void            *data,
   GdkEvent *event;
 
   touch = gdk_wayland_seat_get_touch (seat, id);
+  if (!touch)
+    return;
+
   touch->x = wl_fixed_to_double (x);
   touch->y = wl_fixed_to_double (y);
 
@@ -3381,9 +3390,14 @@ tablet_tool_handle_proximity_in (void                      *data,
   GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet);
   GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
   GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
-  GdkSurface *surface = wl_surface_get_user_data (wsurface);
+  GdkSurface *surface;
   GdkEvent *event;
 
+  if (!wsurface)
+    return;
+
+  surface = wl_surface_get_user_data (wsurface);
+
   if (!surface)
       return;
   if (!GDK_IS_SURFACE (surface))
@@ -3427,6 +3441,9 @@ tablet_tool_handle_proximity_out (void                      *data,
   GdkWaylandTabletData *tablet = tool->current_tablet;
   GdkEvent *event;
 
+  if (!tablet)
+    return;
+
   GDK_SEAT_NOTE (tool->seat, EVENTS,
             g_message ("proximity out, seat %p, tool %d", tool->seat,
                        gdk_device_tool_get_tool_type (tool->tool)));
@@ -3490,7 +3507,7 @@ tablet_tool_handle_down (void                      *data,
   GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tool->seat);
   GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
 
-  if (!tablet->pointer_info.focus)
+  if (!tablet || !tablet->pointer_info.focus)
     return;
 
   _gdk_wayland_display_update_serial (display_wayland, serial);
@@ -3507,7 +3524,7 @@ tablet_tool_handle_up (void                      *data,
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
 
-  if (!tablet->pointer_info.focus)
+  if (!tablet || !tablet->pointer_info.focus)
     return;
 
   tablet_create_button_event_frame (tablet, GDK_BUTTON_RELEASE, GDK_BUTTON_PRIMARY);
@@ -3524,6 +3541,9 @@ tablet_tool_handle_motion (void                      *data,
   GdkWaylandTabletData *tablet = tool->current_tablet;
   GdkEvent *event;
 
+  if (!tablet)
+    return;
+
   tablet->pointer_info.surface_x = wl_fixed_to_double (sx);
   tablet->pointer_info.surface_y = wl_fixed_to_double (sy);
 
@@ -3551,7 +3571,12 @@ tablet_tool_handle_pressure (void                      *data,
 {
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
-  int axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE];
+  int axis_index;
+
+  if (!tablet)
+    return;
+
+  axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE];
 
   _gdk_device_translate_axis (tablet->stylus_device, axis_index,
                               pressure, &tablet->axes[GDK_AXIS_PRESSURE]);
@@ -3568,7 +3593,12 @@ tablet_tool_handle_distance (void                      *data,
 {
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
-  int axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE];
+  int axis_index;
+
+  if (!tablet)
+    return;
+
+  axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE];
 
   _gdk_device_translate_axis (tablet->stylus_device, axis_index,
                               distance, &tablet->axes[GDK_AXIS_DISTANCE]);
@@ -3586,8 +3616,14 @@ tablet_tool_handle_tilt (void                      *data,
 {
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
-  int xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT];
-  int ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT];
+  int xtilt_axis_index;
+  int ytilt_axis_index;
+
+  if (!tablet)
+    return;
+
+  xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT];
+  ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT];
 
   _gdk_device_translate_axis (tablet->stylus_device, xtilt_axis_index,
                               wl_fixed_to_double (xtilt),
@@ -3614,7 +3650,7 @@ tablet_tool_handle_button (void                      *data,
   GdkEventType evtype;
   guint n_button;
 
-  if (!tablet->pointer_info.focus)
+  if (!tablet || !tablet->pointer_info.focus)
     return;
 
   tablet->pointer_info.press_serial = serial;
@@ -3645,7 +3681,12 @@ tablet_tool_handle_rotation (void                      *data,
 {
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
-  int axis_index = tablet->axis_indices[GDK_AXIS_ROTATION];
+  int axis_index;
+
+  if (!tablet)
+    return;
+
+  axis_index = tablet->axis_indices[GDK_AXIS_ROTATION];
 
   _gdk_device_translate_axis (tablet->stylus_device, axis_index,
                               wl_fixed_to_double (degrees),
@@ -3664,7 +3705,12 @@ tablet_tool_handle_slider (void                      *data,
 {
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
-  int axis_index = tablet->axis_indices[GDK_AXIS_SLIDER];
+  int axis_index;
+
+  if (!tablet)
+    return;
+
+  axis_index = tablet->axis_indices[GDK_AXIS_SLIDER];
 
   _gdk_device_translate_axis (tablet->stylus_device, axis_index,
                               position, &tablet->axes[GDK_AXIS_SLIDER]);
@@ -3682,9 +3728,14 @@ tablet_tool_handle_wheel (void                      *data,
 {
   GdkWaylandTabletToolData *tool = data;
   GdkWaylandTabletData *tablet = tool->current_tablet;
-  GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
+  GdkWaylandSeat *seat;
   GdkEvent *event;
 
+  if (!tablet)
+    return;
+
+  seat = GDK_WAYLAND_SEAT (tablet->seat);
+
   GDK_SEAT_NOTE (seat, EVENTS,
             g_message ("tablet tool %d wheel %d/%d",
                        gdk_device_tool_get_tool_type (tool->tool), degrees, clicks));
@@ -3724,6 +3775,9 @@ tablet_tool_handle_frame (void                      *data,
   GdkWaylandTabletData *tablet = tool->current_tablet;
   GdkEvent *frame_event;
 
+  if (!tablet)
+    return;
+
   GDK_SEAT_NOTE (tablet->seat, EVENTS,
             g_message ("tablet frame, time %d", time));